#include "liocom.h"

namespace Lio {

Socket::Socket(BYTE revision, BYTE version):
		sockid(INVALID_SOCKET),
		localport(0),
		remoteport(0),
		ip(0)
{
	WSAStartup(MAKEWORD(revision,version), &wsaData);
	memset(strip, 0, sizeof(strip));
}
Socket::~Socket()
{
	disconnect();
	WSACleanup();
}
BOOL Socket::connect(const char * remoteIP, WORD remotePort, WORD localPort)
{
	int optval=1;
	disconnect();

	if(!remoteIP)
	{
		ip=htonl(INADDR_ANY);
		strcpy(strip,IP_NOTSPECIF);
	}
	else if(strcmp(remoteIP,"localhost")==0)
	{
		ip=htonl(INADDR_LOOPBACK);
		strcpy(strip,IP_LOCALHOST);
	}
	else if(strcmp(remoteIP,"broadcast")==0)
	{
		ip=htonl(INADDR_BROADCAST);
		strcpy(strip,IP_BROADCAST);
	}
	else
	{
		ULONG tmp=inet_addr(remoteIP);
		if(tmp==INADDR_NONE)
		{
			ip=htonl(INADDR_BROADCAST);
			strcpy(strip,IP_BROADCAST);
			return FALSE;
		}
		ip=tmp;
		strcpy(strip,remoteIP);
	}
	localport=localPort;
	remoteport=remotePort;

	if(!localport)
		sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	else
		sockid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockid == INVALID_SOCKET)
	{
		error=WSAGetLastError();
		return FALSE;
	}
	ClearStruct(servaddr);
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(remoteport);
	servaddr.sin_addr.s_addr = ip;
	if(!localport)
	{
		if(::connect(sockid, (SOCKADDR*) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
		{
			error=WSAGetLastError();
			return FALSE;
		}
	}
	else
	{
		ClearStruct(localaddr);
		localaddr.sin_family = AF_INET;
		localaddr.sin_port = htons(localport);
		localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
		if (bind(sockid, (SOCKADDR*) &localaddr, sizeof(localaddr))==SOCKET_ERROR||
			setsockopt(sockid, SOL_SOCKET, SO_BROADCAST, (const char *) &optval, sizeof(int))==SOCKET_ERROR)// Enable broadcast
		{
			error=WSAGetLastError();
			return FALSE;
		}
	}
	error=NO_ERROR;
	return TRUE;
}
void Socket::disconnect()
{
	if(sockid!=INVALID_SOCKET)
    {
		closesocket(sockid);
		sockid = INVALID_SOCKET;
    }
}
BOOL Socket::receive(void *buffer, int n)
{
	int bytes=::recv(sockid, (char *)buffer, n, 0);
	if(bytes!=n)
		error=WSAGetLastError();
	else
		error=NO_ERROR;
	return !error;
}
BOOL Socket::send(const void *buffer, int n)
{
	int bytes;
	if(!localport)
		bytes=::send(sockid, (const char *)buffer, n, 0);
	else
		bytes=::sendto(sockid, (const char *)buffer, n, 0, (struct sockaddr *) &servaddr, sizeof(servaddr));
	if(bytes!=n)
		error=WSAGetLastError();
	else
		error=NO_ERROR;
	return !error;
}


/*
#include <stdio.h>
#include "winsock2.h"

void main() {
  //----------------------
  // Initialize Winsock
  WSADATA wsaData;
  int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  if (iResult != NO_ERROR)
    printf("Error at WSAStartup()\n");

  //----------------------
  // Create a SOCKET for connecting to server
  SOCKET ConnectSocket;
  ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (ConnectSocket == INVALID_SOCKET) {
    printf("Error at socket(): %ld\n", WSAGetLastError());
    WSACleanup();
    return;
  }

  //----------------------
  // The sockaddr_in structure specifies the address family,
  // IP address, and port of the server to be connected to.
  sockaddr_in clientService; 
  clientService.sin_family = AF_INET;
  clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
  clientService.sin_port = htons( 27015 );

  //----------------------
  // Connect to server.
  if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {
    printf( "Failed to connect.\n" );
    WSACleanup();
    return;
  }

  //----------------------
  // Declare and initialize variables.
  int bytesSent;
  int bytesRecv = SOCKET_ERROR;
  char sendbuf[32] = "Client: Sending data.";
  char recvbuf[32] = "";

  //----------------------
  // Send and receive data.
  bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
  printf( "Bytes Sent: %ld\n", bytesSent );

  while( bytesRecv == SOCKET_ERROR ) {
    bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );
    if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {
      printf( "Connection Closed.\n");
      break;
    }
    printf( "Bytes Recv: %ld\n", bytesRecv );
  }

  WSACleanup();
  return;
}
*/

}; // namespace Lio {